﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
//using System.Data.SqlClient;
using System.Data.Common;
using System.Threading;
using System.Collections;
using MySql.Data.MySqlClient;
using System.IO;
using System.Windows;

/// <summary>
///zld修改说明
///1.只支持MySQL数据库，只支持MysqlClient访问方式；
///2.createThreadProcess时，创建连接，如果创建失败，则返回空，抛出异常；
///3.检测连接是否超时时，判断该连接是否正在使用，不使用才释放连接；
///4.增加日志记录；
///</summary>
namespace DateBaseConnectionPool
{
    /// <summary>
    /// 数据库连接池，默认数据库连接方案是ODBC
    /// </summary>
    public class ConnectionPool : IDisposable
    {
        #region 变量定义
        //属性
        private int _realFormPool;//连接池中存在的实际连接数(包含失效的连接)
        private int _potentRealFormPool;//连接池中存在的实际连接数(有效的实际连接)
        private int _spareRealFormPool;//空闲的实际连接
        private int _useRealFormPool;//已分配的实际连接
        private int _readOnlyFormPool;//连接池已经分配多少只读连接
        private int _useFormPool;//已经分配出去的连接数
        private int _spareFormPool;//目前可以提供的连接数
        private int _maxConnection;//最大连接数，最大可以创建的连接数目
        private int _minConnection;//最小连接数
        private int _seepConnection;//每次创建连接的连接数
        private int _keepRealConnection;//保留的实际空闲连接，以攻可能出现的ReadOnly使用，当空闲连接不足该数值时，连接池将创建seepConnection个连接
        private int _exist = 20;//每个连接生存期限 20分钟
        private int _maxRepeatDegree = 5;//可以被重复使用次数（引用记数），当连接被重复分配该值所表示的次数时，该连接将不能被分配出去
        //当连接池的连接被分配尽时，连接池会在已经分配出去的连接中，重复分配连接（引用记数）。来缓解连接池压力
        private DateTime _startTime;//服务启动时间
        private string _connString = null;//连接字符串
        private ConnTypeEnum _connType;//连接池连接类型
        private PoolState _ps;//连接池状态
        //内部对象
        private List<ConnStruct> al_All = new List<ConnStruct>();//实际连接
        private Hashtable hs_UseConn = new Hashtable();//正在使用的连接
        private System.Timers.Timer time;//监视器记时器

        private Thread threadCreate;//创建线程
        private bool isThreadCheckRun = false;
        //private Mutex mUnique = new Mutex();
        //EventHandler 
        private static Mutex M_al_ALL = new Mutex();     //创建互斥量，取代lock
        private static Mutex M_hs_Use = new Mutex();     //创建互斥量，取代lock
        private static Mutex M_this = new Mutex();     //创建互斥量，取代lock

        #endregion
        //--------------------------------------------------------------------
        #region 构造方法 与 初始化函数

        public ConnectionPool(string DataBase, string DataSource)
        {
            StringBuilder connectionString = new StringBuilder("Database=");
            connectionString.Append(string.Format("{0};", DataBase));
            connectionString.Append(string.Format("Data Source= {0};", DataSource));
            connectionString.Append("Persist Security Info= yes;UserId=root;PWD=;charset=utf8");
            InitConnectionPool(connectionString.ToString(), ConnTypeEnum.MySqlClient, 10, 5, 3, 3, 3);
        }

        public ConnectionPool(string DataBase, string DataSource, string SecurityInfo, string UserId, string Psw, string charset)
        {
            StringBuilder connectionString = new StringBuilder("Database=");
            connectionString.Append(string.Format("{0};", DataBase));
            connectionString.Append(string.Format("Data Source= {0};",DataSource));
            connectionString.Append(string.Format("Persist Security Info= {0};", SecurityInfo));
            connectionString.Append(string.Format("UserId={0};",UserId));
            connectionString.Append(string.Format("PWD={0};", Psw));
            connectionString.Append(string.Format("charset={0};MultipleActiveResultSets=true", charset));
            InitConnectionPool(connectionString.ToString(), ConnTypeEnum.MySqlClient, 10, 5, 3, 3, 3);
        }
        /// <summary>
        /// 初始化连接池
        /// </summary>
        /// <param name="connectionString">数据库连接字符串</param>
        public ConnectionPool(string connectionString)
        { InitConnectionPool(connectionString, ConnTypeEnum.MySqlClient, 10, 5, 3, 3, 3); }
        /// <summary>
        /// 初始化连接池
        /// </summary>
        /// <param name="connectionString">数据库连接字符串</param>
        /// <param name="cte">数据库连接类型</param>
        public ConnectionPool(string connectionString, ConnTypeEnum cte)
        { InitConnectionPool(connectionString, cte, 10, 5, 3, 3, 3); }
        /// <summary>
        /// 初始化连接池
        /// </summary>
        /// <param name="connectionString">数据库连接字符串</param>
        /// <param name="cte">数据库连接类型</param>
        /// <param name="maxConnection">最大连接数，最大可以创建的连接数目</param>
        /// <param name="minConnection">最小连接数</param>
        public ConnectionPool(string connectionString, ConnTypeEnum cte, int maxConnection, int minConnection)
        { InitConnectionPool(connectionString, cte, maxConnection, minConnection, 3, 3, 3); }
        /// <summary>
        /// 初始化连接池
        /// </summary>
        /// <param name="connectionString">数据库连接字符串</param>
        /// <param name="cte">数据库连接类型</param>
        /// <param name="maxConnection">最大连接数，最大可以创建的连接数目</param>
        /// <param name="minConnection">最小连接数</param>
        /// <param name="seepConnection">每次创建连接的连接数</param>
        /// <param name="keepConnection">保留连接数，当空闲连接不足该数值时，连接池将创建seepConnection个连接</param>
        public ConnectionPool(string connectionString, ConnTypeEnum cte, int maxConnection, int minConnection, int seepConnection, int keepConnection)
        { InitConnectionPool(connectionString, cte, maxConnection, minConnection, seepConnection, keepConnection, 5); }
        /// <summary>
        /// 初始化连接池
        /// </summary>
        /// <param name="connectionString">数据库连接字符串</param>
        /// <param name="cte">数据库连接类型</param>
        /// <param name="maxConnection">最大连接数，最大可以创建的连接数目</param>
        /// <param name="minConnection">最小连接数</param>
        /// <param name="seepConnection">每次创建连接的连接数</param>
        /// <param name="keepConnection">保留连接数，当空闲连接不足该数值时，连接池将创建seepConnection个连接</param>
        /// <param name="keepRealConnection">当空闲的实际连接不足该值时创建连接，直到达到最大连接数</param>
        public ConnectionPool(string connectionString, ConnTypeEnum cte, int maxConnection, int minConnection, int seepConnection, int keepConnection, int keepRealConnection)
        { InitConnectionPool(connectionString, cte, maxConnection, minConnection, seepConnection, keepConnection, keepRealConnection); }

        /// <summary>
        /// 初始化函数
        /// </summary>
        protected void InitConnectionPool(string connectionString, ConnTypeEnum cte, int maxConnection, int minConnection, int seepConnection, int keepConnection, int keepRealConnection)
        {
            if (cte == ConnTypeEnum.None)
                throw new ConnTypeExecption();//参数不能是None

            _ps = PoolState.UnInitialize;
            this._connString = connectionString;
            this._connType = cte;
            this._minConnection = minConnection;
            this._seepConnection = seepConnection;
            this._keepRealConnection = keepRealConnection;
            this._maxConnection = maxConnection;
            this.time = new System.Timers.Timer(200);
            this.time.Stop();
            this.time.Elapsed += new System.Timers.ElapsedEventHandler(time_Elapsed);
            this.threadCreate = new Thread(new ThreadStart(createThreadProcess));
        }

        #endregion
        //--------------------------------------------------------------------
        #region 属性部分
        /// <summary>
        /// 连接池服务状态
        /// </summary>
        public PoolState State
        { get { return _ps; } }
        /// <summary>
        /// 连接池是否启动，改变该属性将相当于调用StartServices或StopServices方法，注：只有连接池处于Run，Stop状态情况下才可以对此属性赋值
        /// </summary>
        public bool Enable
        {
            get
            {
                if (_ps == PoolState.Run)
                    return true;
                else
                    return false;
            }
            set
            {
                if (_ps == PoolState.Run || _ps == PoolState.Stop)
                    if (value == true)
                        StartServices();
                    else
                        StopServices();
                else
                    throw new SetValueExecption();//只有连接池处于Run，Stop状态情况下才可以对此属性赋值
            }
        }
        /// <summary>
        /// 得到或设置连接类型
        /// </summary>
        public ConnTypeEnum ConnectionType
        {
            get { return _connType; }
            set
            {
                if (_ps == PoolState.Stop)
                    _connType = value;
                else
                    throw new SetValueExecption();//只有在Stop状态时才可操作
            }
        }
        /// <summary>
        /// 连接池使用的连接字符串
        /// </summary>
        public string ConnectionString
        {
            get { return _connString; }
            set
            {
                if (_ps == PoolState.Stop)
                    _connString = value;
                else
                    throw new SetValueExecption();//只有在Stop状态时才可操作
            }
        }
        /// <summary>
        /// 得到服务器运行时间
        /// </summary>
        public DateTime RunTime
        {
            get
            {
                if (_ps == PoolState.Stop)
                    return new DateTime(DateTime.Now.Ticks - _startTime.Ticks);
                else
                    return new DateTime(0);
            }
        }
        /// <summary>
        /// 最小连接数
        /// </summary>
        public int MinConnection
        {
            get { return _minConnection; }
            set
            {
                if (value < _maxConnection && value > 0 && value >= _keepRealConnection)
                    _minConnection = value;
                else
                    throw new ParameterBoundExecption();//参数范围应该在 0~MaxConnection之间，并且应该大于KeepConnection
            }
        }
        /// <summary>
        /// 最大连接数，最大可以创建的连接数目
        /// </summary>
        public int MaxConnection
        {
            get { return _maxConnection; }
            set
            {
                if (value >= _minConnection && value > 0)
                    _maxConnection = value;
                else
                    throw new ParameterBoundExecption();//参数范围错误，参数应该大于minConnection
            }
        }
        /// <summary>
        /// 每次创建连接的连接数
        /// </summary>
        public int SeepConnection
        {
            get { return _seepConnection; }
            set
            {
                if (value > 0 && value < _maxConnection)
                    _seepConnection = value;
                else
                    throw new ParameterBoundExecption();//创建连接的步长应大于0，同时小于MaxConnection
            }
        }
        /// <summary>
        /// 保留的实际空闲连接，以攻可能出现的ReadOnly使用
        /// </summary>
        public int KeepRealConnection
        {
            get { return _keepRealConnection; }
            set
            {
                if (value >= 0 && value < _maxConnection)
                    _keepRealConnection = value;
                else
                    throw new ParameterBoundExecption();//保留连接数应大于等于0，同时小于MaxConnection
            }
        }
        /// <summary>
        /// 自动清理连接池的时间间隔
        /// </summary>
        public double Interval
        {
            get { return time.Interval; }
            set { time.Interval = value; }
        }
        /// <summary>
        /// 每个连接生存期限(单位分钟)，默认20分钟
        /// </summary>
        public int Exist
        {
            get { return _exist; }
            set
            {
                if (_ps == PoolState.Stop)
                    _exist = value;
                else
                    throw new PoolNotStopException();//只有在Stop状态下才可以操作
            }
        }
        /// <summary>
        /// 可以被重复使用次数（引用记数）当连接被重复分配该值所表示的次数时，该连接将不能被分配出去。
        /// 当连接池的连接被分配尽时，连接池会在已经分配出去的连接中，重复分配连接（引用记数）。来缓解连接池压力
        /// </summary>
        public int MaxRepeatDegree
        {
            get { return _maxRepeatDegree; }
            set
            {
                if (value >= 0)
                    _maxRepeatDegree = value;
                else
                    throw new ParameterBoundExecption();//重复引用次数应大于等于0
            }
        }
        /// <summary>
        /// 连接池最多可以提供多少个连接
        /// </summary>
        public int MaxConnectionFormPool
        { get { return _maxConnection * _maxRepeatDegree; } }
        /// <summary>
        /// 连接池中存在的实际连接数(有效的实际连接)
        /// </summary>
        public int PotentRealFormPool
        {
            get
            {
                if (_ps == PoolState.Run)
                    return _potentRealFormPool;
                else
                    throw new PoolNotRunException();//连接池处在非运行中
            }
        }
        /// <summary>
        /// 连接池中存在的实际连接数(包含失效的连接)
        /// </summary>
        public int RealFormPool
        {
            get
            {
                if (_ps == PoolState.Run)
                    return _realFormPool;
                else
                    throw new PoolNotRunException();//连接池处在非运行中
            }
        }
        /// <summary>
        /// 空闲的实际连接
        /// </summary>
        public int SpareRealFormPool
        {
            get
            {
                if (_ps == PoolState.Run)
                    return _spareRealFormPool;
                else
                    throw new PoolNotRunException();//连接池处在非运行中
            }
        }
        /// <summary>
        /// 已分配的实际连接
        /// </summary>
        public int UseRealFormPool
        {
            get
            {
                if (_ps == PoolState.Run)
                    return _useRealFormPool;
                else
                    throw new PoolNotRunException();//连接池处在非运行中
            }
        }
        /// <summary>
        /// 连接池已经分配多少只读连接
        /// </summary>
        public int ReadOnlyFormPool
        {
            get
            {
                if (_ps == PoolState.Run)
                    return _readOnlyFormPool;
                else
                    throw new PoolNotRunException();//连接池处在非运行中
            }
        }
        /// <summary>
        /// 已经分配的连接数
        /// </summary>
        public int UseFormPool
        {
            get
            {
                if (_ps == PoolState.Run)
                    return _useFormPool;
                else
                    throw new PoolNotRunException();//连接池处在非运行中
            }
        }
        /// <summary>
        /// 目前可以提供的连接数
        /// </summary>
        public int SpareFormPool
        {
            get
            {
                if (_ps == PoolState.Run)
                    return _spareFormPool;
                else
                    throw new PoolNotRunException();//连接池处在非运行中
            }
        }

        #endregion
        //--------------------------------------------------------------------
        #region 启动服务 与 终止服务
        /// <summary>
        /// 启动服务，线程安全，同步调用
        /// </summary>
        public void StartServices()
        { StartServices(false); }
        /// <summary>
        /// 启动服务，线程安全
        /// </summary>
        /// <param name="ansy">是否异步调用True为是，异步调用指，用户调用该方法后，无须等待创建结束就可继续做其他操作</param>
        public void StartServices(bool ansy)
        {
            //lock (this)
                M_this.WaitOne();
            {
                createThreadMode = 0;//工作模式0
                createThreadProcessRun = true;
                createThreadProcessTemp = _minConnection;
                if (_ps == PoolState.UnInitialize)
                    threadCreate.Start();
                else if (_ps == PoolState.Stop)
                    threadCreate.Interrupt();
                else
                {
                    WriteLogFile("初始化连接池时，服务已经启动");
                    throw new PoolNotStopException();//服务已经运行或者未完全结束
                }
                time.Start();
            }
            M_this.ReleaseMutex();

            if (!ansy)
            {
                int count = 10;
                while (threadCreate.ThreadState != ThreadState.WaitSleepJoin && count>0)
                {
                    count--;    //最多等待500ms
                    Thread.Sleep(50);
                }//等待可能存在的创建线程结束
            }
        }
        /// <summary>
        /// 停止服务，线程安全
        /// </summary>
        public void StopServices()
        { StopServices(false); }
        /// <summary>
        /// 停止服务，线程安全
        /// <param name="needs">是否必须退出；如果指定为false与StartServices()功能相同，如果指定为true。将未收回的连接资源关闭，这将是危险的。认为可能你的程序正在使用此资源。</param>
        /// </summary>
        public void StopServices(bool needs)
        {
            //lock (this)
            M_this.WaitOne();
            {
                if (_ps == PoolState.Run)
                {
                    //lock (hs_UseConn)
                    M_hs_Use.WaitOne();
                    {
                        if (needs == true)//必须退出
                            hs_UseConn.Clear();
                        else
                            if (hs_UseConn.Count != 0)
                            {
                                WriteLogFile("停止连接池时，还有连接未释放");
                                throw new ResCallBackException();//连接池资源未全部回收
                            }
                    }
                    M_hs_Use.ReleaseMutex();

                    int count = 5;
                    while (isThreadCheckRun && count>0) 
                    {
                        count--;    //最多等250ms
                        Thread.Sleep(50);
                    }//等待timer事件结束
                    isThreadCheckRun = false;
                    time.Stop();
                    WriteLogFile("检测定时器停止");

                    count = 5;
                    while (threadCreate.ThreadState != ThreadState.WaitSleepJoin && count >0) 
                    { 
                        count--;
                        Thread.Sleep(50); 
                    }//等待可能存在的创建线程结束
                    createThreadProcessRun = false;
                    WriteLogFile("创建连接线程停止0");

                    //lock (al_All)
                    M_al_ALL.WaitOne();
                    {
                        for (int i = 0; i < al_All.Count; i++)
                            al_All[i].Dispose();
                        al_All.Clear();
                    }
                    M_al_ALL.ReleaseMutex();
                    _ps = PoolState.Stop;
                    WriteLogFile("停止连接池服务");
                }
                else
                {
                    WriteLogFile("停止连接时，服务未启动");
                    throw new PoolNotRunException();//服务未启动
                }
            }
            M_this.ReleaseMutex();
            UpdateAttribute();//更新属性
        }

        public void Dispose()
        {
            try
            {
                this.StopServices();
                threadCreate.Abort();
            }
            catch (Exception e) { }
        }

        #endregion
        //--------------------------------------------------------------------
        #region 获得连接 与 释放连接
        /// <summary>
        /// 在连接池中申请一个连接，使用None级别，线程安全
        /// </summary>
        /// <param name="gui">发起者</param>
        /// <returns>返回申请到的连接</returns>
        public DbConnection GetConnectionFormPool(object key)
        { return GetConnectionFormPool(key, ConnLevel.None); }
        /// <summary>
        /// 在连接池中申请一个连接，线程安全
        /// </summary>
        /// <param name="key">申请者</param>
        /// <param name="cl">申请的连接级别</param>
        /// <returns>返回申请到的连接</returns>
        public DbConnection GetConnectionFormPool(object key, ConnLevel cl)
        {
            //lock (this)
            M_this.WaitOne();
            {
                if (_ps != PoolState.Run)
                {
                    WriteLogFile("获取连接时，连接池服务停止");
                    //throw new StateException();//服务状态错误
                    M_this.ReleaseMutex();
                    return null;
                }
                if (hs_UseConn.Count == MaxConnectionFormPool)
                {
                    WriteLogFile("获取连接时，连接已经饱和");
                    //throw new PoolFullException();//连接池已经饱和，不能提供连接
                    M_this.ReleaseMutex();
                    return null;
                }
                if (hs_UseConn.ContainsKey(key))
                {
                    WriteLogFile("获取连接时，key重复");
                    //throw new KeyExecption();//一个key对象只能申请一个连接
                    M_this.ReleaseMutex();
                    return null;
                }

                M_this.ReleaseMutex();
                return GetConnectionFormPool_None(key);//None级别

                //if (cl == ConnLevel.ReadOnly)
                //{
                //    M_this.ReleaseMutex();
                //    return GetConnectionFormPool_ReadOnly(key);//ReadOnly级别
                //}
                //else if (cl == ConnLevel.High)
                //{
                //    M_this.ReleaseMutex();
                //    return GetConnectionFormPool_High(key);//High级别
                //}
                //else if (cl == ConnLevel.None)
                //{
                    
                //}
                //else
                //{
                //    M_this.ReleaseMutex();
                //    return GetConnectionFormPool_Bottom(key);//Bottom级别
                //}
            }
            //M_this.ReleaseMutex();
        }
        /// <summary>
        /// 申请一个连接资源，只读方式，线程安全
        /// </summary>
        /// <param name="key">申请者</param>
        /// <returns>申请到的连接对象</returns>
        protected DbConnection GetConnectionFormPool_ReadOnly(object key)
        {
            ConnStruct cs = null;
            for (int i = 0; i < al_All.Count; i++)
            {
                cs = al_All[i];
                if (cs.Enable == false || cs.Allot == false || cs.UseDegree == _maxRepeatDegree || cs.IsUse == true)
                    continue;
                return GetConnectionFormPool_Return(key, cs, ConnLevel.ReadOnly); //返回得到的连接
            }
            return GetConnectionFormPool_Return(key, null, ConnLevel.ReadOnly);
        }
        /// <summary>
        /// 申请一个连接资源，优先级-高，线程安全
        /// </summary>
        /// <param name="key">申请者</param>
        /// <returns>申请到的连接对象</returns>
        //protected DbConnection GetConnectionFormPool_High(object key)
        //{
        //    ConnStruct cs = null;
        //    ConnStruct csTemp = null;

        //    for (int i = 0; i < al_All.Count; i++)
        //    {
        //        csTemp = al_All[i];
        //        if (csTemp.Enable == false || csTemp.Allot == false || csTemp.UseDegree == _maxRepeatDegree)//不可以分配跳出本次循环。
        //        {
        //            csTemp = null;
        //            continue;
        //        }
        //        if (csTemp.UseDegree == 0)//得到最合适的
        //        {
        //            cs = csTemp;
        //            break;
        //        }
        //        else//不是最合适的放置到最佳选择中
        //        {
        //            if (cs != null)
        //            {
        //                if (csTemp.UseDegree < cs.UseDegree)
        //                    //与上一个最佳选择选出一个最佳的放置到cs中
        //                    cs = csTemp;
        //            }
        //            else
        //                cs = csTemp;
        //        }
        //    }
        //    return GetConnectionFormPool_Return(key, cs, ConnLevel.High);//返回最合适的连接
        //}
        /// <summary>
        /// 申请一个连接资源，优先级-中，线程安全
        /// </summary>
        /// <param name="key">申请者</param>
        /// <returns>申请到的连接对象</returns>
        protected DbConnection GetConnectionFormPool_None(object key)
        {
            List<ConnStruct> al = new List<ConnStruct>();
            al.Clear();
            ConnStruct cs = null;
            for (int i = 0; i < al_All.Count; i++)
            {
                cs = al_All[i];
                if (cs.Enable == false || cs.Allot == false || cs.UseDegree == _maxRepeatDegree || cs.IsUse == true)//不可以分配跳出本次循环。
                    continue;
                else
                {
                    cs.Repeat();
                    hs_UseConn.Add(key, cs);
                    return cs.Connection;
                    al.Add(cs);
                    break;
                }

                //if (cs.Allot == true)
                //    al.Add(cs);
            }
            if (al.Count == 0)
                return GetConnectionFormPool_Return(key, null, ConnLevel.None);//发出异常
            else
                return GetConnectionFormPool_Return(key, (al[al.Count / 2]), ConnLevel.None);//返回连接
        }
        /// <summary>
        /// 申请一个连接资源，优先级-低，线程安全
        /// </summary>
        /// <param name="key">申请者</param>
        /// <returns>申请到的连接对象</returns>
        //protected DbConnection GetConnectionFormPool_Bottom(object key)
        //{
        //    ConnStruct cs = null;
        //    ConnStruct csTemp = null;

        //    for (int i = 0; i < al_All.Count; i++)
        //    {
        //        csTemp = al_All[i];
        //        if (csTemp.Enable == false || csTemp.Allot == false || csTemp.UseDegree == _maxRepeatDegree)//不可以分配跳出本次循环。
        //        {
        //            csTemp = null;
        //            continue;
        //        }
        //        else//不是最合适的放置到最佳选择中
        //        {
        //            if (cs != null)
        //            {
        //                if (csTemp.UseDegree > cs.UseDegree)
        //                    //与上一个最佳选择选出一个最佳的放置到cs中
        //                    cs = csTemp;
        //            }
        //            else
        //                cs = csTemp;
        //        }
        //    }
        //    return GetConnectionFormPool_Return(key, cs, ConnLevel.Bottom);//返回最合适的连接
        //}
        /// <summary>
        /// 返回DbConnection对象，同时做获得连接时的必要操作
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="cs">ConnStruct对象</param>
        /// <param name="cl">级别</param>
        /// <param name="readOnly">是否为只读属性</param>
        /// <returns></returns>
        private DbConnection GetConnectionFormPool_Return(object key, ConnStruct cs, ConnLevel cl)
        {
            try
            {
                if (cs == null)
                {
                    WriteLogFile("获取连接时，连接池内资源为空");
                    return null;
                    //throw new Exception();
                }
                cs.Repeat();
                hs_UseConn.Add(key, cs);
                if (cl == ConnLevel.ReadOnly)
                {
                    cs.Allot = false;
                    cs.IsRepeat = false;
                }
            }
            catch (Exception e)
            {
                WriteLogFile("获取连接时，连接池内资源耗尽");
                //throw new OccasionExecption();//连接资源耗尽，或错误的访问时机。
                return null;
            }
            finally
            {
                UpdateAttribute();//更新属性
            }
            WriteLogFile(string.Format("分配出一个连接 key={0}",key));
            return cs.Connection;
        }
        /// <summary>
        /// 释放申请的数据库连接对象，线程安全
        /// <param name="key">key表示数据库连接申请者</param>
        /// </summary>
        public void DisposeConnection(object key)
        {
            //lock (hs_UseConn)
            M_hs_Use.WaitOne();
            {
                ConnStruct cs = null;
                if (_ps == PoolState.Run)
                {
                    if (!hs_UseConn.ContainsKey(key))
                    {
                        WriteLogFile("key错误，无法释放连接");
                        //throw new NotKeyExecption();//无法释放，不存在的key
                    }
                    cs = (ConnStruct)hs_UseConn[key];
                    cs.IsRepeat = true;
                    //cs.IsRepeat = false;    //不允许两次分配
                    if (cs.Allot == false)
                        if (cs.Enable == true)
                            cs.Allot = true;
                    cs.Remove();
                    hs_UseConn.Remove(key);
                    WriteLogFile(string.Format("收回一个连接:key = {0}",key));
                }
                else
                {
                    WriteLogFile("释放连接时，服务未启动");
                    throw new PoolNotRunException();//服务未启动
                }
            }
            M_hs_Use.ReleaseMutex();
            UpdateAttribute();//更新属性
        }

        #endregion
        //--------------------------------------------------------------------
        #region 私有方法
        private int createThreadMode = 0;//创建线程工作模式
        private int createThreadProcessTemp = 0;//需要创建的连接数
        private bool createThreadProcessRun = false;//是否决定创建线程将继续工作，如果不继续工作则线程会将自己处于阻止状态
        /// <summary>
        /// 创建线程
        /// </summary>
        private void createThreadProcess()
        {
            bool join = false;
            bool FirstConnect = true;
            int createThreadProcessTemp_inside = createThreadProcessTemp;
            _ps = PoolState.Initialize;
            while (true)
            {
                try
                {
                    join = false;
                    _ps = PoolState.Run;
                    if (createThreadProcessRun == false)
                    {//遇到终止命令
                        WriteLogFile("创建连接线程终止");
                        try { threadCreate.Join(); }
                        catch (Exception e) 
                        {
                            WriteLogFile("创建连接线程终止出错");
                        }
                    }
                    else
                    {
                        if (createThreadMode == 0)
                        {
                            //------------------------begin mode  创建模式
                            //lock (al_All)
                            M_al_ALL.WaitOne();
                            {
                                if (al_All.Count < createThreadProcessTemp_inside)
                                {
                                    ConnStruct Tmp = CreateConnection(_connString, _connType);
                                    if (Tmp != null)
                                    {
                                        al_All.Add(Tmp);
                                        StringBuilder s = new StringBuilder("创建一个连接：");
                                        s.Append(_connString);
                                        s.Append(string.Format("  ,总连接数:{0}", al_All.Count));
                                        WriteLogFile(s.ToString());
                                        if (FirstConnect)
                                        {
                                            FirstConnect = false;
                                            try
                                            {
                                                string CheckTableExits = "Select * from Connect_TestTable";
                                                MySqlCommand conn = new MySqlCommand(CheckTableExits, (MySqlConnection)Tmp.Connection);
                                                conn.ExecuteNonQuery();
                                                WriteLogFile(string.Format("测试表存在 :{0}", CheckTableExits));
                                            }
                                            catch
                                            {
                                                string CreateTestTable = "create table if not exists Connect_TestTable(No int(4),C1 int(4))";
                                                try
                                                {

                                                    MySqlCommand conn = new MySqlCommand(CreateTestTable, (MySqlConnection)Tmp.Connection);
                                                    conn.ExecuteNonQuery();
                                                    string InsertTestLine = "Insert into Connect_TestTable (No,C1)VALUES(1,1)";
                                                    MySqlCommand InsertConn = new MySqlCommand(InsertTestLine, (MySqlConnection)Tmp.Connection);
                                                    InsertConn.ExecuteNonQuery();
                                                    WriteLogFile(string.Format("创建ConnectTestTable成功 :{0}", CreateTestTable));
                                                }
                                                catch
                                                {
                                                    WriteLogFile(string.Format("创建ConnectTestTable失败 :{0}", CreateTestTable));
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        WriteLogFile(string.Format("连接数据库出错:{0}", _connString));
                                        //throw new ConnectionErrorExecption();
                                    }
                                }
                                else
                                    join = true;
                            }
                            M_al_ALL.ReleaseMutex();
                            //------------------------end mode
                        }
                        else if (createThreadMode == 1)
                        {
                            //------------------------begin mode  增加模式
                            //lock (al_All)
                            M_al_ALL.WaitOne();
                            {
                                if (createThreadProcessTemp_inside != 0)
                                {
                                    ConnStruct Tmp = CreateConnection(_connString, _connType);
                                    if (Tmp != null)
                                    {
                                        al_All.Add(Tmp);
                                        createThreadProcessTemp_inside--;
                                        StringBuilder s = new StringBuilder("创建一个连接：");
                                        s.Append(_connString);
                                        s.Append(string.Format("  ,总连接数:{0}", al_All.Count));
                                        WriteLogFile(s.ToString());
                                    }
                                    else
                                    {
                                        WriteLogFile(string.Format("连接数据库出错:{0}", _connString));
                                        //throw new ConnectionErrorExecption(); 
                                    }
                                }
                                else
                                    join = true;
                            }
                            M_al_ALL.ReleaseMutex();
                            //------------------------end mode
                        }
                        else
                            join = true;
                        //-------------------------------------------------------------------------
                        if (join == true)
                        {
                            UpdateAttribute();//更新属性
                            try
                            {
                                createThreadProcessTemp = 0;
                                threadCreate.Join();
                            }
                            catch (Exception e)
                            { createThreadProcessTemp_inside = createThreadProcessTemp; }//得到传入的变量
                        }
                    }
                }
                catch (Exception  ex){
                    Console.WriteLine("##" + ex.Message);
                }
            }
        }
        /// <summary>
        /// 检测事件
        /// </summary>
        private void time_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            ConnStruct cs = null;
            time.Stop();//关闭自己
            isThreadCheckRun = true;
            //如果正在执行创建连接则退出
            if (threadCreate.ThreadState != ThreadState.WaitSleepJoin)
            {
                isThreadCheckRun = false;
                time.Start();
                return;
            }
            //------------------------------------------------------
            //lock (al_All)
            M_al_ALL.WaitOne();
            {
                int n = al_All.Count;
                int k = 0;
                for (int i = 0; i < n; i++)
                {
                    cs = al_All[k];                         //
                    TestConnStruct(cs);//测试
                    if (cs.Enable == false && cs.RepeatNow == 0)//没有引用的失效连接
                    {
                        cs.Close();//关闭它
                        al_All.Remove(cs);//删除
                        string s = string.Format("释放一个连接，总连接数：{0}", al_All.Count);
                        WriteLogFile(s);
                    }
                    else k++;
                }
            }
            M_al_ALL.ReleaseMutex();
            //------------------------------------------------------
            UpdateAttribute();//更新属性

            if (_spareRealFormPool < _keepRealConnection)//空闲的实际连接<需要保留的空闲连接数。
                createThreadProcessTemp = GetNumOf(_realFormPool, _seepConnection, _maxConnection);
            else
                createThreadProcessTemp = 0;

            if (createThreadProcessTemp != 0)
            {
                //启动创建线程，工作模式1
                createThreadMode = 1;
                threadCreate.Interrupt();
            }

            isThreadCheckRun = false;
            time.Start();//打开自己
        }
        /// <summary>
        /// 得到当前要增加的量
        /// nowNum 实际的连接
        /// seepNum 需要创建的连接数
        /// maxNum 最大连接数
        /// </summary>
        private int GetNumOf(int nowNum, int seepNum, int maxNum)
        {
            if (maxNum >= nowNum + seepNum)
                return seepNum;
            else
                return maxNum - nowNum;
        }
        /// <summary>
        /// 用指定类型创建连接
        /// </summary>
        /// <param name="conn">连接字符串</param>
        /// <param name="cte">连接类型</param>
        /// <param name="dt">连接超时时间</param>
        /// <returns>返回创建的连接</returns>
        /// zld改，支持Mysql连接，只支持.MySqlClient连接，，不支持ODBC连接
        private ConnStruct CreateConnection(string conn, ConnTypeEnum cte)
        {
            //MySqlConnection db = null;
            DbConnection db = null;
            //if (cte == ConnTypeEnum.Odbc)
            //    db = new System.Data.Odbc.OdbcConnection(conn);//ODBC数据源连接
            //else if (cte == ConnTypeEnum.OleDb)
            //    db = new System.Data.OleDb.OleDbConnection(conn);//OLE DB数据连接
            //else 
            try
            {
                if (cte == ConnTypeEnum.MySqlClient)
                {
                    db = new MySqlConnection(conn);//SqlServer数据库连接
                    ConnStruct cs = new ConnStruct(db, cte, DateTime.Now);
                    cs.Open();
                    return cs;
                }
            }            
            catch (Exception e)
            {
                //throw new ConnectionErrorExecption();
                WriteLogFile(string.Format("建立连接失败:{0}",_connString));
                return null;
            }
            return null;
        }
        /// <summary>
        /// 测试ConnStruct是否过期
        /// </summary>
        /// <param name="cs">被测试的ConnStruct</param>
        private void TestConnStruct(ConnStruct cs)
        {
            //此次被分配出去的连接是否在此次之后失效
            if (cs.IsUse == false)
            {
                if (cs.UseDegree == _maxRepeatDegree)
                {
                    WriteLogFile(string.Format("连接已经超过使用次数:{0}", _maxRepeatDegree));
                    cs.SetConnectionLost();//超过使用次数
                }
                if (cs.CreateTime.AddMinutes(_exist).Ticks <= DateTime.Now.Ticks)
                {
                    WriteLogFile(string.Format("连接已经超过连接时间:{0}", _exist));
                    cs.SetConnectionLost();//连接超时
                }
                if (cs.Connection.State == ConnectionState.Closed)
                {
                    WriteLogFile("连接已经关闭");
                    cs.SetConnectionLost();//连接被关闭
                }

                //数据库连接测试
                string CheckTableExits = "Select * from Connect_TestTable";
                try
                {
                    
                    MySqlCommand conn = new MySqlCommand(CheckTableExits, (MySqlConnection)cs.Connection);
                    conn.ExecuteNonQuery();
                    
                }
                catch
                {
                    WriteLogFile("本连接与数据库断开");
                    cs.SetConnectionLost();//超过使用次数
                }
            }
            
        }
        /// <summary>
        /// 更新属性
        /// </summary>
        private void UpdateAttribute()
        {
            int temp_readOnlyFormPool = 0;//连接池已经分配多少只读连接
            int temp_potentRealFormPool = 0;//连接池中存在的实际连接数(有效的实际连接)
            int temp_spareRealFormPool = 0;//空闲的实际连接
            int temp_useRealFormPool = 0;//已分配的实际连接
            int temp_spareFormPool = MaxConnectionFormPool;//目前可以提供的连接数
            //---------------------------------
            //lock (hs_UseConn)
            M_hs_Use.WaitOne();
            {
                _useFormPool = hs_UseConn.Count;
            }
            M_hs_Use.ReleaseMutex();
            //---------------------------------
            ConnStruct cs = null;
            //int n = 0;
            M_al_ALL.WaitOne();
            lock (al_All)
            {
                _realFormPool = al_All.Count;
                for (int i = 0; i < al_All.Count; i++)
                {
                    cs = al_All[i];
                    //只读
                    if (cs.Allot == false && cs.IsUse == true && cs.IsRepeat == false)
                        temp_readOnlyFormPool++;
                    //有效的实际连接
                    if (cs.Enable == true)
                        temp_potentRealFormPool++;
                    //空闲的实际连接
                    if (cs.Enable == true && cs.IsUse == false)
                        temp_spareRealFormPool++;
                    //已分配的实际连接
                    if (cs.IsUse == true)
                        temp_useRealFormPool++;
                    //目前可以提供的连接数
                    if (cs.Allot == true)
                        temp_spareFormPool = temp_spareFormPool - cs.RepeatNow;
                    else
                        temp_spareFormPool = temp_spareFormPool - _maxRepeatDegree;
                }
            }
            M_al_ALL.ReleaseMutex();
            _readOnlyFormPool = temp_readOnlyFormPool;
            _potentRealFormPool = temp_potentRealFormPool;
            _spareRealFormPool = temp_spareRealFormPool;
            _useRealFormPool = temp_useRealFormPool;
            _spareFormPool = temp_spareFormPool;
        }

        private void WriteLogFile(string WriteString)
        {
            string FileName = System.AppDomain.CurrentDomain.BaseDirectory;
            FileName += "MySqlPoolLog.txt";

            if (File.Exists(FileName))
            {
                FileInfo f = new FileInfo(FileName);
                if (f.Length >= 1024*1024*10)    //文件大于10M,清空文件.
                {
                    File.Delete(FileName);
                }
            }
            try
            {
                FileStream fs = new FileStream(FileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                StreamWriter sw = new StreamWriter(fs);
                DateTime NowTime = DateTime.Now;
                StringBuilder s = new StringBuilder(NowTime.ToString());
                s.Append(string.Format("   {0}", WriteString));
                sw.WriteLine(s);
                sw.Close();
                fs.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("Error:"+e);
            }
       
            
        }
        #endregion
    }
}